package proxy

import (
	"fmt"
	"sync"
	"time"
)

// 实际业务场景：API网关
// 假设我们正在构建一个微服务架构的API网关，需要处理以下需求：
// 1. 身份验证和授权
// 2. 请求限流
// 3. 缓存响应
// 4. 请求日志记录
// 5. 服务熔断

// 使用代理模式可以优雅地实现这些功能。

// Service 抽象主题
type Service interface {
	HandleRequest(url, method string) (int, string)
}

// CoreService 真实主题-核心服务
type CoreService struct{}

func (cs *CoreService) HandleRequest(url, method string) (int, string) {
	// 模拟处理时间
	time.Sleep(100 * time.Millisecond)

	// 模拟不同端点的响应
	switch url {
	case "/api/users":
		if method == "GET" {
			return 200, `[{"id":1,"name":"John"},{"id":2,"name":"Jane"}]`
		}
		return 405, "Method not allowed"
	case "/api/orders":
		if method == "POST" {
			return 201, `{"id": 1001, "status": "created"}`
		}
		return 405, "Method not allowed"
	case "/api/products":
		return 200, `[{"id":101,"name":"Laptop"},{"id":102,"name":"Phone"}]`
	default:
		return 404, "Not found"
	}
}

// APIProxy 代理-API网关
type APIProxy struct {
	realService    Service
	cache          map[string]cacheEntry
	mutex          sync.RWMutex
	rateLimiter    map[string]*rateLimit
	circuitBreaker *circuitbreaker
}

type cacheEntry struct {
	response  string
	expiresAt time.Time
}

type rateLimit struct {
	count    int
	lastTime time.Time
}

type circuitbreaker struct {
	failures    int
	lastFailure time.Time
	state       string // closed open half-open
}

func NewAPIProxy(service Service) *APIProxy {
	return &APIProxy{
		realService:    service,
		cache:          make(map[string]cacheEntry),
		rateLimiter:    make(map[string]*rateLimit),
		circuitBreaker: &circuitbreaker{state: "closed"},
	}
}

// authenticate 身份验证和授权
func (p *APIProxy) authenticate(token string) bool {
	return token == "12345"
}

// rateLimit 限流
func (p *APIProxy) checkRateLimit(clientIP string) bool {

	p.mutex.Lock()
	defer p.mutex.Unlock()

	limiter, ok := p.rateLimiter[clientIP]
	if !ok {
		p.rateLimiter[clientIP] = &rateLimit{count: 1, lastTime: time.Now()}
		return true
	}

	// 重置计数器
	if time.Since(limiter.lastTime) > time.Second {
		limiter.count = 0
		limiter.lastTime = time.Now()
	}

	// 5次/秒
	if limiter.count >= 5 {
		return false
	}
	limiter.count++
	return true
}

// 3. 缓存管理
func (p *APIProxy) checkCache(key string) (string, bool) {
	p.mutex.RLock()
	defer p.mutex.RUnlock()

	entry, exists := p.cache[key]
	if exists && time.Now().Before(entry.expiresAt) {
		return entry.response, true
	}
	return "", false
}

func (p *APIProxy) setCache(key, response string) {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	p.cache[key] = cacheEntry{
		response:  response,
		expiresAt: time.Now().Add(30 * time.Second), // 缓存30秒
	}
}

// 4. 熔断器
func (p *APIProxy) checkCircuitBreaker() bool {
	now := time.Now()

	switch p.circuitBreaker.state {
	case "closed":
		return true
	case "open":
		if now.Sub(p.circuitBreaker.lastFailure) > 10*time.Second {
			p.circuitBreaker.state = "half-open"
			return true
		}
		return false
	case "half-open":
		return true
	default:
		return false
	}
}

func (p *APIProxy) updateCircuitBreaker(success bool) {
	if success {
		if p.circuitBreaker.state == "half-open" {
			p.circuitBreaker.state = "closed"
			p.circuitBreaker.failures = 0
		}
	} else {
		p.circuitBreaker.failures++
		p.circuitBreaker.lastFailure = time.Now()

		if p.circuitBreaker.failures >= 3 {
			p.circuitBreaker.state = "open"
		}
	}
}

// ========= 代理请求处理 =========
func (p *APIProxy) HandleRequest(url, method string) (int, string) {
	// 模拟从请求中获取客户端信息
	clientIP := "192.168.1.100"
	token := "12345" // 模拟有效token

	// 1. 认证检查
	if !p.authenticate(token) {
		return 401, "Unauthorized"
	}

	// 2. 限流检查
	if !p.checkRateLimit(clientIP) {
		return 429, "Too many requests"
	}

	// 3. 缓存检查（仅对GET请求）
	if method == "GET" {
		if cached, ok := p.checkCache(url); ok {
			fmt.Println("返回缓存响应")
			return 200, cached
		}
	}

	// 4. 熔断检查
	if !p.checkCircuitBreaker() {
		return 503, "Service unavailable (circuit breaker open)"
	}

	// 5. 调用真实服务
	start := time.Now()
	status, response := p.realService.HandleRequest(url, method)
	elapsed := time.Since(start)

	// 6. 更新熔断器状态
	p.updateCircuitBreaker(status == 200 || status == 201)

	// 7. 记录日志
	fmt.Printf("请求处理: %s %s | 状态: %d | 耗时: %v\n", method, url, status, elapsed)

	// 8. 缓存有效响应
	if method == "GET" && (status == 200 || status == 201) {
		p.setCache(url, response)
	}

	return status, response
}
